/*
 * Copyright (c) 2011 Ondrej Lapacek
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

/**
 * @author      Ondrej Lapacek
 * @version     1.0, 09/12/11
 * @since       1.0
 */

package cz.muni.fi.android.assistivecamera.osm;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.location.Location;
import cz.muni.fi.android.assistivecamera.osm.model.Node;
import cz.muni.fi.android.assistivecamera.osm.model.OsmData;
import cz.muni.fi.android.assistivecamera.osm.model.Primitive;
import cz.muni.fi.android.assistivecamera.osm.model.Relation;
import cz.muni.fi.android.assistivecamera.osm.model.Way;

public class OpenStreetMapXmlHandler extends DefaultHandler {
	
	private Primitive currentPrim;
    private Map<Long, Node> nodes = new TreeMap<Long, Node>();
    private Map<Long, Way> ways = new TreeMap<Long, Way>();
    private Map<Long, Relation> relations = new TreeMap<Long, Relation>();

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		super.startElement(uri, localName, qName, attributes);
		
		if (qName.equalsIgnoreCase("tag")) {
			String key = attributes.getValue("k");
            String val = attributes.getValue("v");
            currentPrim.setTag(key, val);
		} else if (qName.equalsIgnoreCase("node")) {
			long id = Long.parseLong(attributes.getValue("id"));
            Location latlon = new Location("myself");
            double lat = Double.parseDouble(attributes.getValue("lat"));
            latlon.setLatitude(lat);
            double lon = Double.parseDouble(attributes.getValue("lon"));
            latlon.setLongitude(lon);
            currentPrim = new Node(id, latlon);
		} else if (qName.equalsIgnoreCase("nd")) {
			String ndIdStr = attributes.getValue("ref");
            Long ndId = Long.parseLong(ndIdStr);
            ((Way) currentPrim).addNode(nodes.get(ndId));
		} else if (qName.equalsIgnoreCase("way")) {
			long id = Long.parseLong(attributes.getValue("id"));
            currentPrim = new Way(id);
		} else if (qName.equalsIgnoreCase("member")) {
			if ("outer".equals(attributes.getValue("role"))) {
				String ndIdStr = attributes.getValue("ref");
	            Long ndId = Long.parseLong(ndIdStr);
	            ((Relation) currentPrim).addOuterWay(ways.get(ndId));
			} else if ("inner".equals(attributes.getValue("role"))) {
				String ndIdStr = attributes.getValue("ref");
	            Long ndId = Long.parseLong(ndIdStr);
	            ((Relation) currentPrim).addInnerWay(ways.get(ndId));
			}
		} else if (qName.equalsIgnoreCase("relation")) {
			long id = Long.parseLong(attributes.getValue("id"));
            currentPrim = new Relation(id);
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		super.endElement(uri, localName, qName);
		
		if (qName.equalsIgnoreCase("node")) {
            nodes.put(currentPrim.getId(), (Node) currentPrim);
        } else if(qName.equalsIgnoreCase("way")) {
            ways.put(currentPrim.getId(), (Way) currentPrim);
        } else if(qName.equalsIgnoreCase("relation")) {
        	relations.put(currentPrim.getId(), (Relation) currentPrim);
        }
	}

	public OsmData getData() {
		return findBuildings(new OsmData (nodes, ways, relations));
	}
	
	private OsmData findBuildings(OsmData result) {
		
	    Map<Long, Way> ways = new HashMap<Long, Way>();
	    
	    if (result.getRelations().size() > 0) {
	    	Iterator<Entry<Long, Relation>> relationIterator = result.getRelations().entrySet().iterator();
	    
	    	while (relationIterator.hasNext()) {
	        	Map.Entry<Long, Relation> relationRecord = relationIterator.next();
	        	
	        	if ("yes".equals(relationRecord.getValue().getTag("building"))) {
	        		relationRecord.getValue().getOuterWayList().get(0).addTags(relationRecord.getValue().getTags());
	        		ways.put(relationRecord.getValue().getOuterWayList().get(0).getId(), 
	        				relationRecord.getValue().getOuterWayList().get(0));
	        	}
	        }
	    }
	    	
	    if (result.getWays().size() > 0) {
	    	Iterator<Entry<Long, Way>> wayIterator = result.getWays().entrySet().iterator();
	    
	    	while (wayIterator.hasNext()) {
	        	Map.Entry<Long, Way> wayRecord = wayIterator.next();
	        	
	        	if ("yes".equals(wayRecord.getValue().getTag("building"))) {
	        		ways.put(wayRecord.getKey(), wayRecord.getValue());
	        	}
	        }
	    }
	    
	    return new OsmData(null, ways, null);
    }
}
